//奇偶表
int parity_table[][6] = {
  { 1, 1, 1, 1, 1, 1 },
  { 1, 1, 0, 1, 0, 0 },
  { 1, 1, 0, 0, 1, 0 },
  { 1, 1, 0, 0, 0, 1 },
  { 1, 0, 1, 1, 0, 0 },
  { 1, 0, 0, 1, 1, 0 },
  { 1, 0, 0, 0, 1, 1 },
  { 1, 0, 1, 0, 1, 0 },
  { 1, 0, 1, 0, 0, 1 },
  { 1, 0, 0, 1, 0, 1 }
};

//编码表
char encoding_table[10][3][8] = {
  { "0001101", "0100111", "1110010" },
  { "0011001", "0110011", "1100110" },
  { "0010011", "0011011", "1101100" },
  { "0111101", "0100001", "1000010" },
  { "0100011", "0011101", "1011100" },
  { "0110001", "0111001", "1001110" },
  { "0101111", "0000101", "1010000" },
  { "0111011", "0010001", "1000100" },
  { "0110111", "0001001", "1001000" },
  { "0001011", "0010111", "1110100" }
};

//奇偶数组
int odd[6] = { 0 };
int even[6] = { 0 };

/**
 * @brief 得到奇偶数
 *
 * 传入要编码的数据，然后找出奇偶位
 *
 * @param pcode int* 你要编码的数据
 * @param podd int* 奇数保存的数组
 * @param peven int* 偶数保存的数组
 * @return void
 */
void get_odd_even(int* pcode, int* podd, int* peven) {

  //(0,2,4,6,8,10)
  for (int a = 0; a < 6; a++) {
    peven[a] = pcode[a * 2];
  }

  //(1,3,5,7,9,11)
  for (int a = 0; a < 6; a++) {
    podd[a] = pcode[a * 2 + 1];
  }
}


/**
 * @brief 计算校验位
 *
 * 根据奇偶位计算校验位
 *
 * @param podd int* 奇数数组
 * @param peven int* 偶数数组
 * @return int 计算的结果
 */
int calculate_check_digit(int* podd, int* peven) {
  int oddsum = 0;
  int evensum = 0;
  for (int i = 0; i < 6; i++) {
    oddsum += podd[i];
    evensum += peven[i];
  }
  int total = oddsum * 3 + evensum;
  return (10 - (total % 10)) % 10;
}

/**
 * @brief 对数据进行编码
 *
 * 生成条形码的0/1序列
 *
 * @param poutput char* 保存0/1序列的数组
 * @param pcode int* 偶数数组
 * @return int 计算的结果
 */
void encode(char* poutput, int* pcode) {
  char left[42] = { 0 };
  char right[42] = { 0 };
  for (int i = 0; i < 6; i++) {
    for (int a = 0; a < 7; a++) {  //根据第一位判断奇偶
      left[a + i * 7] = encoding_table[pcode[i + 1]][1 - parity_table[pcode[0]][i]][a];
    }
    for (int a = 0; a < 7; a++) {
      right[a + i * 7] = encoding_table[pcode[i + 7]][2][a];
    }
  }

  poutput[0] = '1';
  poutput[1] = '0';
  poutput[2] = '1';

  memcpy(poutput + 3, left, 42);

  //中间分隔符
  poutput[45] = '0';
  poutput[46] = '1';
  poutput[47] = '0';
  poutput[48] = '1';
  poutput[49] = '0';

  memcpy(poutput + 50, right, 42);

  //结束符
  poutput[92] = '1';
  poutput[93] = '0';
  poutput[94] = '1';
}

/**
 * @brief 对编码的0/1进行解码
 *
 * 传入0/1序列进行解码
 *
 * @param pcode char* 保存0/1序列的数组(95)
 * @param data int* 保存解码的数据(13)
 * @return bool true成功   false失败
 */
bool decoding(char* pcode, int* data) {

  //每位的解码状态
  bool ok[13] = { 0 };

  //判断方向
  char str[8] = { 0 };
  str[7] = '\0';

  //保存方向
  bool zhengxiang_flag = false;

  //假设最后是校验位，复制到str中
  memcpy(str, pcode + 85, 7);
  //Serial.println(str);
  for (int i = 0; i < 10; i++) {
    for (int a = 0; a < 6; a++) {
      if (strstr(encoding_table[i][2], str) != NULL) {  //只看右边的编码，有的话方向正确
        zhengxiang_flag = true;
        Serial.println("Zheng-xiang!");
        //保存校验位
        data[12] = i;
        break;
      }
    }
  }

  //如果反向
  if (!zhengxiang_flag) {
    Serial.println("Fan-xiang!");
    char temp;
    for (int i = 0; i < 43; i++) {
      temp = pcode[i];
      pcode[i] = pcode[94 - i];
      pcode[94 - i] = temp;
    }
  }

  //开始解右边的数据

  for (int b = 0; b < 5; b++) {
    memcpy(str, pcode + 50 + b * 7, 7);
    //遍历寻找值
    for (int i = 0; i < 10; i++) {
      if (strstr(encoding_table[i][2], str) != NULL) {  //右边的编码
        ok[7 + b] = true;
        data[7 + b] = i;
        break;
      }
    }
  }

  //左侧数据

  //判断奇偶模式
  //遍历编码表，记录每个位的奇偶性并找到对于的数字
  int mode[6] = { 0 };
  for (int i = 0; i < 6; i++) {  //左侧6个数字
    memcpy(str, pcode + 3 + i * 7, 7);
    for (int j = 0; j < 10; j++) {
      for (int k = 0; k < 2; k++) {
        if (strstr(encoding_table[j][k], str) != NULL) {
          ok[i + 1] = true;
          data[i + 1] = j;
          break;
        }
      }
    }
    for (int a = 0; a < 2; a++) {     //奇偶性
      for (int b = 0; b < 10; b++) {  //0-9数字
        if (strstr(encoding_table[b][a], str) != NULL) {
          mode[i] = 1 - a;
        }
      }
    }
  }


  //匹配奇偶表，找到第一个数字
  //奇偶表的第一个都是1,可以不用判断
  int first_num = 0;
  for (int i = 0; i < 10; i++) {
    if (mode[1] == parity_table[i][1] && mode[2] == parity_table[i][2] && mode[3] == parity_table[i][3] && mode[4] == parity_table[i][4] && mode[5] == parity_table[i][5]) {
      first_num = i;
      ok[0] = true;
      break;
    }
  }

  //保存第一个数字
  data[0] = first_num;

  //检测是否转换成功
  for (int i = 0; i < 13; i++) {
    if (ok[i] != 1) {
      return true;
    }
  }
  return true;
}

